#ifndef __GPIO_H__
#define __GPIO_H__

#include <stdint.h>

#define __IO volatile

#define PERIPH_BASE        (0x40000000UL)

/* RCC */ 
#define RCC_BASE           (PERIPH_BASE + 0x21000UL)

typedef struct {
    __IO uint32_t CR;         // 0x00
    __IO uint32_t CFGR;       // 0x04
    __IO uint32_t CIR;        // 0x08
    __IO uint32_t APB2RSTR;   // 0x0C
    __IO uint32_t APB1RSTR;   // 0x10
    __IO uint32_t AHBENR;     // 0x14
    __IO uint32_t APB2ENR;    // 0x18
    __IO uint32_t APB1ENR;    // 0x1C
    __IO uint32_t BDCR;       // 0x20
    __IO uint32_t CSR;        // 0x24
} RCC_t;

#define RCC     ((RCC_t *)RCC_BASE)
#define RCC_APB2ENR_IOPAEN (1UL << 2)

/* GPIO */
#define PERIPH_APB2_BASE   (PERIPH_BASE + 0x10000UL)
#define GPIOA_BASE         (PERIPH_APB2_BASE + 0x0800UL)

#define GPIO_CRL_INPUT_ANALOG    0x00
#define GPIO_CRL_INPUT_FLOATING  0x04
#define GPIO_CRL_INPUT_PULL      0x08
#define GPIO_CRL_OUT_PP_10MHZ    0x01
#define GPIO_CRL_OUT_PP_2MHZ     0x02
#define GPIO_CRL_OUT_PP_50MHZ    0x03
#define GPIO_CRL_OUT_OD_10MHZ    0x05

typedef struct {
    __IO uint32_t CRL;
    __IO uint32_t CRH;
    __IO uint32_t IDR;
    __IO uint32_t ODR;
    __IO uint32_t BSRR;
    __IO uint32_t BRR;
    __IO uint32_t LCKR;
} GPIO_t;

#define GPIOA   ((GPIO_t *)GPIOA_BASE)

#define GPIOA_CRL_CLR(a)   (0xFUL << (4 * (a)))
#define GPIOA_CRL_SET(a, v)   ((v) << (4 * (a)))
#define BSRR_BS_PIN(a)     (1U << (a))
#define BSRR_BR_PIN(a)     (1U << ((a) + 16))

#endif